package com.sayice.robotconflict.game.object;

import com.sayice.robotconflict.common.util.SpringContextUtil;
import com.sayice.robotconflict.entity.PlayerEntity;
import com.sayice.robotconflict.entity.RobotEntity;
import com.sayice.robotconflict.game.Game;
import com.sayice.robotconflict.game.msg.Message;
import com.sayice.robotconflict.service.BagService;
import com.sayice.robotconflict.service.PlayerService;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelId;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 玩家
 *
 * @author shubing
 */
public class Player implements Comparable<Player> {
    /**
     * 下一个虚拟玩家号
     */
    private static final AtomicInteger NEXT_VIRTUAL_NUM = new AtomicInteger();
    
    private static final PlayerService PLAYER_SERVICE = SpringContextUtil.getBean(PlayerService.class);
    
    private static final BagService BAG_SERVICE = SpringContextUtil.getBean(BagService.class);
    
    /**
     * ID
     */
    public final String id;
    
    /**
     * 玩家名
     */
    public String name;
    
    /**
     * 对局次数
     */
    public int gameNum;
    
    /**
     * 胜率 (%)
     */
    public int winRate;
    
    /**
     * 携带的机器人
     */
    public final Map<Integer, Robot> robots = new HashMap<>(8);
    
    // 上面的属性初始化自数据库
    
    /**
     * 是否是虚拟的 (人机)
     */
    public final boolean isVirtual;
    
    /**
     * 玩家状态
     */
    public AtomicReference<State> state = new AtomicReference<>(State.IDLE);
    
    /**
     * 对局中的所属队伍
     */
    public volatile Team team;
    
    /**
     * 当前控制的机器人
     */
    public volatile Robot robot;
    
    /**
     * 与客户端通信的 Channel
     */
    private volatile Channel channel;
    
    /**
     * 下线监听器
     */
    private final ChannelFutureListener offlineListener = future -> {
        if (team != null) {
            // TODO bug: room有时会空指针
            team.room.onlineCount.decrementAndGet();
            setControl(-1);
        }
    };
    
    /**
     * 创建一个在线玩家
     */
    public Player(String id, Channel channel) {
        PlayerEntity playerEntity = PLAYER_SERVICE.queryById(id);
        List<RobotEntity> robotEntities = BAG_SERVICE.queryCarriedRobots(id);
        this.id = playerEntity.getId();
        this.name = playerEntity.getName();
        this.gameNum = playerEntity.getGameNum();
        this.winRate = playerEntity.getWinRate();
        setCarriedRobots(robotEntities);
        this.isVirtual = false;
        this.channel = channel;
        this.channel.closeFuture().addListener(offlineListener);
    }
    
    /**
     * 创建一个虚拟玩家
     */
    private Player(List<RobotEntity> robotEntities) {
        Random random = new Random();
        this.id = Thread.currentThread().getName() + NEXT_VIRTUAL_NUM.getAndIncrement();
        this.name = "";
        this.gameNum = random.nextInt(1001);
        this.winRate = (int) Math.round(random.nextInt(gameNum + 1) / (double) gameNum * 100);
        for (int i = 0; i < robotEntities.size(); i++) {
            Robot robot = new Robot(robotEntities.get(i), this, i);
            this.robots.put(i, robot);
        }
        this.isVirtual = true;
        this.channel = null;
    }
    
    /**
     * 创建一个虚拟玩家 (人机)
     *
     * @return 具有默认逻辑的机器人的虚拟玩家
     */
    public static Player newVirtual() {
        List<RobotEntity> robotEntities = BAG_SERVICE.queryInitRobots();
        return new Player(robotEntities);
    }
    
    /**
     * 创建指定数量的虚拟玩家 (人机)
     *
     * @param num 数量
     * @return 具有默认逻辑的机器人的虚拟玩家列表
     */
    public static List<Player> newVirtualPlayers(int num) {
        if (num <= 0) {
            return Collections.emptyList();
        }
        List<RobotEntity> robotEntities = BAG_SERVICE.queryInitRobots();
        List<Player> players = new ArrayList<>();
        for (int i = 0; i < num; i++) {
            players.add(new Player(robotEntities));
        }
        return players;
    }
    
    public ChannelId channelId() {
        return isVirtual ? null : channel.id();
    }
    
    public ChannelFuture closeFuture() {
        return isVirtual ? null : channel.closeFuture();
    }
    
    /**
     * 对局后重置
     */
    public void reset() {
        team = null;
        robots.values().forEach(Robot::reset);
    }
    
    /**
     * 恢复状态，更新channel
     *
     * @param channel 新的channel
     */
    public void restoreState(Channel channel) {
        Channel oldChannel = this.channel;
        this.channel = channel;
        this.channel.closeFuture().addListener(offlineListener);
        State playerState = state.get();
        if (playerState == State.MATCHING_1 || playerState == State.MATCHING_3 || playerState == State.MATCHING_5) {
            send(new Message("action", "enterMatch", null));
        } else if (playerState == State.GAMING) {
            // 发送对局信息
            send(new Message("game", "surrenderedCount", team.surrenderedCount()));
            send(new Message("game_info", null, team.room.gameInfo(team)));
        }
        oldChannel.close();
    }
    
    /**
     * 设置携带的机器人
     */
    public void setCarriedRobots(List<RobotEntity> robotEntities) {
        robots.clear();
        robot = null;
        if (robotEntities.isEmpty()) {
            return;
        }
        Robot firstRobot = new Robot(robotEntities.get(0), this, 0);
        robot = firstRobot;
        firstRobot.controlled = true;
        robots.put(0, firstRobot);
        int robotsCount = Math.min(robotEntities.size(), Game.MAX_CARRY);
        for (int i = 1; i < robotsCount; i++) {
            Robot robot = new Robot(robotEntities.get(i), this, i);
            robots.put(i, robot);
        }
    }
    
    /**
     * 设置当前控制的机器人
     *
     * @param seq 机器人序号 (从0开始)
     */
    public void setControl(int seq) {
        Robot robot = robots.get(seq);
        if (this.robot != null) {
            this.robot.controlled = false;
        }
        if (robot != null) {
            robot.controlled = true;
        }
        this.robot = robot;
    }
    
    /**
     * 向客户端发送消息
     *
     * @param msg 消息
     */
    public void send(Message msg) {
        if (!isVirtual) {
            channel.writeAndFlush(msg.toJson());
        }
    }
    
    @Override
    public int hashCode() {
        return System.identityHashCode(this);
    }
    
    @Override
    public boolean equals(Object o) {
        return this == o;
    }
    
    @Override
    public int compareTo(Player o) {
        return id.compareTo(o.id);
    }
    
    /**
     * 玩家状态
     */
    public enum State {
        /**
         * 空闲
         */
        IDLE,
        
        /**
         * 组队中
         */
        TEAMING,
        
        /**
         * 1v1 匹配中
         */
        MATCHING_1,
        
        /**
         * 3v3 匹配中
         */
        MATCHING_3,
        
        /**
         * 5v5 匹配中
         */
        MATCHING_5,
        
        /**
         * 对局中
         */
        GAMING
    }
}
